/**
 * @Function html转pdf工具类
 * @ProjectName credit-data-platform
 * @PackageName com.py.credit.utils
 * @FileName HtmlToPdfUtils.java
 * @Date 2018年7月30日下午5:54:22
 * @Author Min DongXv
 * @Copyright (c) 2018, 金电联行 All Rights Reserved.
 */
package com.py.credit.utils;

import com.py.credit.common.logs.ExceptionLogger;
import com.py.credit.common.rest.RestServiceResult;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.concurrent.ThreadLocalRandom;

/**
 * @Function html转pdf工具类
 * @ClassName HtmlToPdfUtils
 * @Date 2018年7月30日 下午5:54:22
 * @Author Min DongXv
 */
public class HtmlToPdfUtils {

    private static final long DAY_MILL_SECONDS = 24 * 60 * 60 * 1000L;

    private static final int NUM_9999 = 9999;
    // 缓冲区大小
    private static final int BYTE_SIZE = 1024;

    private HtmlToPdfUtils() {
    }

    /**
     * @param toolPath wkhtmltopdf 工具安装位置
     * @param srcPath  网页位置
     * @param destPath 生成pdf位置
     * @param pageSize 打印纸张大小 默认A4
     * @Function windows环境 html转pdf
     * @FileName HtmlToPdfUtils.java
     * @MethodName convent
     * @Date 2018年7月11日 下午5:25:09
     * @Author Min DongXv
     */
    public static boolean convent(String toolPath, String srcPath, String destPath, String fileName, String options) {
        File file = new File(destPath);
        // 如果pdf保存路径不存在，则创建路径
        if (!file.exists()) {
            file.mkdirs();
        }
        if (StringUtils.isBlank(options)) {
            options = " -s A4 --image-quality 1000 --javascript-delay 10000 ";
        }
        // 拼接执行参数
        StringBuilder cmd = new StringBuilder();
        cmd.append(toolPath);
        cmd.append(options).append(" ").append(srcPath).append(" ").append(destPath).append(fileName).append(".pdf");
        boolean result = true;
        try {
            Runtime.getRuntime().exec(cmd.toString());
            return result;
        } catch (Exception e) {
            result = false;
            return result;
        }
    }

    /**
     * @param jsPath              脚本地址(具体到脚本，例如:F:\puppeteer\winjs.js)
     * @param htmlUrl             网页位置
     * @param destPath            生成pdf位置(最后不带斜杠，例如:F:/pdfPath)
     * @param fileName            文件名称(文件名带后缀)
     * @param paper               A4,A3
     * @param displayHeaderFooter 是否展示页眉页脚 true不展示 false展示
     * @param googlePath          谷歌浏览器位置 window环境是不需要填的
     * @Function Google html转pdf工具
     * @FileName HtmlToPdfUtils.java
     * @MethodName googleConvent
     * @Date
     * @Author Min DongXv
     */
    public static boolean googleConvent(String jsPath, String htmlUrl, String destPath, String fileName, String paper,
                                        boolean displayHeaderFooter, String googlePath) {
        File file = new File(destPath);
        // 默认A4纸
        if (StringUtils.isEmpty(paper)) {
            paper = "A4";
        }
        // 如果pdf保存路径不存在，则创建路径
        if (!file.exists()) {
            file.mkdirs();
        }
        // 拼接执行参数
        StringBuilder cmd = new StringBuilder(150);
        cmd.append("node ").append(jsPath).append(" ").append(htmlUrl).append(" ").append(destPath)
                .append(File.separator).append(fileName).append(" ").append(paper).append(" ")
                .append(String.valueOf(displayHeaderFooter));
        if (StringUtils.isNotBlank(googlePath)) {
            cmd.append(" ").append(googlePath);
        }
        try {
            Runtime.getRuntime().exec(cmd.toString());
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    /**
     * @param jsPath              脚本地址(具体到脚本，例如:F:\puppeteer\winjs.js)
     * @param htmlUrl             网页位置
     * @param destPath            生成pdf位置(最后不带斜杠，例如:F:/pdfPath)
     * @param fileName            文件名称(文件名带后缀)
     * @param paper               A4,A3
     * @param displayHeaderFooter 是否展示页眉页脚 true不展示 false展示
     * @param googlePath          谷歌浏览器位置 window环境是不需要填的
     * @Function Google html转pdf工具(同步方法，有执行返回，但响应时间较长)
     * @FileName HtmlToPdfUtils.java
     * @MethodName googleConventSync
     * @Date
     * @Author Min DongXv
     */
    public static boolean googleConventSync(String jsPath, String htmlUrl, String destPath, String fileName,
                                            String paper, boolean displayHeaderFooter, String googlePath) {
        File file = new File(destPath);
        // 默认A4纸
        if (StringUtils.isEmpty(paper)) {
            paper = "A4";
        }
        // 如果pdf保存路径不存在，则创建路径
        if (!file.exists()) {
            file.mkdirs();
        }
        // 拼接执行参数
        StringBuilder cmd = new StringBuilder(150);
        boolean result = true;
        cmd.append("node ").append(jsPath).append(" ").append(htmlUrl).append(" ").append(destPath)
                .append(File.separator).append(fileName).append(" ").append(paper).append(" ")
                .append(String.valueOf(displayHeaderFooter));
        if (StringUtils.isNotBlank(googlePath)) {
            cmd.append(" ").append(googlePath);
        }
        InputStream is = null;
        try {
            Process process = Runtime.getRuntime().exec(cmd.toString());
            is = process.getInputStream();
            if (null != is) {
                is.close();
            }
            if (0 != process.waitFor()) {
                result = false;
            }
            return result;
        } catch (Exception e) {
            ExceptionLogger.error("HtmlToPdfUtils#googleConventSync",
                    "信用评价模块PDF生成失败！" + "命令:" + cmd.toString() + " 错误原因" + e.getMessage());
            result = false;
            return result;
        }
    }

    /**
     * @param absolutepath 文件存放地址(最后不带斜杠)
     * @param fileName     文件名称(文件名带后缀)
     * @param response     response
     * @Function 文件下载
     * @FileName HtmlToPdfUtils.java
     * @MethodName download
     * @Date
     * @Author Min DongXv
     */
    public static RestServiceResult<Object> download(String absolutepath, String fileName,
                                                     HttpServletResponse response) {
        RestServiceResult<Object> result = new RestServiceResult<>();
        String path = absolutepath + File.separator + fileName;
        if (StringUtils.isBlank(fileName) || !(new File(path).exists())) {
            result.setCode(RestServiceResult.CODE_UNKNOW);
            result.setMsg("报告已不存在,请重新生成");
            return result;
        }
        FileUtil.downloadFile(path, response);
        return result;
    }

    /**
     * @param absolutepath 文件存放地址(最后不带斜杠)
     * @param fileName     文件名称(文件名带后缀)
     * @param response     response
     * @Function 文件预览
     * @FileName HtmlToPdfUtils.java
     * @MethodName preview
     * @Date
     * @Author Min DongXv
     */
    public static RestServiceResult<Object> preview(String absolutepath, String fileName,
                                                    HttpServletResponse response) {
        RestServiceResult<Object> result = new RestServiceResult<>();
        response.setContentType("application/pdf");
        response.setHeader("Content-Disposition", "inline;fileName=" + fileName + ".pdf");
        if (StringUtils.isBlank(fileName) || !(new File(absolutepath + fileName).exists())) {
            result.setCode(RestServiceResult.CODE_UNKNOW);
            result.setMsg("报告已不存在,请重新生成");
            return result;
        }
        File pdf = new File(absolutepath + fileName);
        try (ServletOutputStream outputStream = response.getOutputStream();
             FileInputStream fis = new FileInputStream(pdf)) {
            response.setContentLength((int) pdf.length());
            byte[] buffer = new byte[BYTE_SIZE];
            while ((fis.read(buffer, 0, BYTE_SIZE)) != -1) {
                outputStream.write(buffer, 0, BYTE_SIZE);
            }
            outputStream.flush();
            return result;
        } catch (Exception e) {
            result.setCode(RestServiceResult.CODE_UNKNOW);
            result.setMsg("文件读取异常");
            return result;
        }
    }

    /**
     * @param absolutepath 文件存放地址(最后不带斜杠)
     * @param fileName     文件名称(文件名带后缀)
     * @Function 检查文件是否存在
     * @FileName HtmlToPdfUtils.java
     * @MethodName fileExist
     * @Date
     * @Author Min DongXv
     */
    public static RestServiceResult<Object> fileExist(String absolutepath, String fileName) {
        RestServiceResult<Object> result = new RestServiceResult<>();
        if (StringUtils.isBlank(fileName) || !(new File(absolutepath + fileName).exists())) {
            result.setCode(RestServiceResult.CODE_UNKNOW);
            result.setMsg("报告已不存在,请重新生成");
            return result;
        }
        return result;
    }

    /**
     * @param prefix 文件前缀
     * @Function 生成唯一文件名
     * @FileName HtmlToPdfUtils.java
     * @MethodName createFileName
     * @Date
     * @Author Min DongXv
     */
    public static String createFileName(String prefix, String split) {
        StringBuilder sb = new StringBuilder(32);
        String time = new SimpleDateFormat("yyyyMMdd").format(new java.util.Date());
        String head = String.format("%09d", System.currentTimeMillis() % DAY_MILL_SECONDS);
        String body = String.format("%03d", Thread.currentThread().getId());
        String foot = String.format("%04d", ThreadLocalRandom.current().nextInt(NUM_9999));
        split = StringUtils.isNotBlank(split) ? split : "";
        sb.append(prefix).append(time).append(split).append(head).append(split).append(body).append(split).append(foot);
        return sb.toString();
    }
}
